//
//  WmcUploadQueueManager.swift
//  YPWatermarkCamera
//
//  Created by 周诗松 on 2022/4/1.
//

import Alamofire
//import AliyunOSSiOS
import Foundation
import Moya
import NSObject_Rx
import RxRelay
import RxSwift
import UIKit
import YPBedrock
import YPNetwork

class WmcUploadQueueManager: NSObject {
    // Internal

    static let shared = WmcUploadQueueManager()

    /// 开始上传
    private(set) var startSubject: PublishSubject<Void> = .init()

    /// 开始自动同步
    private(set) var startAutoUploadSubject: PublishSubject<Void> = .init()

    /// 监听上传的总进度
    private(set) var progressSubject: PublishSubject<Double> = .init()

    /// 上传成功
    private(set) var completionSubject: PublishSubject<Void> = .init()

    /// 上传失败
    private(set) var failureSubject: PublishSubject<Void> = .init()

    /// 取消上传任务
    private(set) var cancelAllTasksSubject: PublishSubject<Void> = .init()

    /// 上个上传任务提交成功
    private(set) var taskUploadSuccessSubject: PublishSubject<WmcUploadImageV2Model> = .init()

    /// 上传状态
    private(set) var uploading: Bool = false

    /// 等待上传队列
    private(set) var awaitUploadQueue: [WmcUploadImageV2Model] = []

    static func appendUploadTask(path: String, model: WmcMediaUploadResourceParameterModel) {
        model.appId = 101
        if !WmcLoginManager.shared.isLogin {
            return
        }
        WmcPreferenceSettingsManager.querySyncSwitchConfig { r in
            if !r.isOpen {
                return
            }

            // !!!: 这两行代码看似脱裤子放屁，其实是为了解决传给后端浮点数后精度丢失导致签名验证失败
            let watermarkInfo = WmcWatermarkDetailModel.deserialize(from: model.wmcInfo)?.toJSON()
            model.wmcInfo = watermarkInfo

            let imageModel = WmcUploadImageV2Model()
            imageModel.photoPath = path
            imageModel.previewImagePath = model.previewImagePath
            imageModel.parameters = model.toJSON() ?? [:]
            imageModel.syncInfo = WmcUploadQueueManager.shared.querySyncData(configList: r.list)

            WmcUploadQueueV2DBManager.insert(model: imageModel) { isSuccess in
                if isSuccess {
                    shared.appendUploadQueue(model: imageModel)
                }
            }
        } failure: { error in
            WmcHudManager.toast(error)
        }
    }

    /// 新建上传任务
    /// - Parameters:
    ///   - image: 图片
    ///   - projectId: 项目id
    ///   - watermarkType: 水印类型
    static func appendUploadTask(image: UIImage,
                                 model: WmcMediaUploadResourceParameterModel)
    {
        guard let imageData = image.yp.pngData else { return }

        let groupFolder = WmcUploadQueueManager.shared.imageFilePath
        let filePath = groupFolder.yp.appendPathComponent("\(image.hashValue)")

        let writePath = YPSystem.Documents.Path.yp.appendPathComponent(filePath)
        try? imageData.write(to: writePath.yp.fileUrl)

        appendUploadTask(path: filePath, model: model)
    }

    /// 继续上传
    /// - Parameter model: 缓存model
    static func continueUploadTask(model: WmcUploadImageV2Model) {
        let networkType = YPNetworkReachability.queryNetworkReachabilityType()
        if networkType == .unknow || networkType == .notReachable {
            DispatchQueue.main.async {
                shared.failureSubject.onNext(())
                WmcHudManager.toast("网络不佳，请稍后再试")
            }
            return
        }

        shared.appendUploadQueue(model: model)
    }

    /// 开始自动上传
    static func startAutoUploadTask() {
        WmcUploadQueueV2DBManager.query { list in
            list.forEach { item in
                item.uploading = true
            }
            shared.awaitUploadQueue = list
            shared.totalTaskCount = shared.awaitUploadQueue.count
            shared.startUploadTask()
            DispatchQueue.main.async {
                shared.startAutoUploadSubject.onNext(())
            }
        }
    }

    /// 停止所有任务
    static func stopAllTask() {
        shared.applyRequest?.moyaCancellable?.cancel()
        shared.currentUploadingRequest?.cancel()
        shared.resetAllStatus()
        shared.cancelAllTasksSubject.onNext(())
    }

    /// 查询有多少个正在上传中
    /// - Returns: 个数
    static func queryUploadingTaskCount() -> Int {
        return shared.awaitUploadQueue.count
    }

    /// 清理无效的任务
    /*
     static func cleanInvalidTask() {
         WmcPreferenceSettingsManager.queryTeamSyncConfigCache { list in
             var teamIds: [Int] = []
             list.forEach { item in
                 if item.isSync {
                     teamIds.append(item.albumId)
                 }
             }
             var taskTemp: [WmcUploadImageV2Model] = []
             WmcUploadQueueManager.shared.awaitUploadQueue.forEach { item in
                 if WmcUploadQueueManager.shared.currentUploadTask?.uuid == item.uuid {
                     taskTemp.append(item)
                 } else {
                     if let configList = item.syncInfo?["albumBasicsInfo"] as? [[String: Any]] {}
                 }
             }
         }
     }
      */

    // Fileprivate

    /// 日志系统
    fileprivate func log(_ log: String) {
        WmcLogManager.DebugLog(type: .uploadQueueManager, log: log)
    }

    // Private

    private var fileManager: FileManager = .default

    /// 申请上传重试次数
    private var applyRetryCount = 0

    /// 上传阿里云重试次数
    private var uploadRetryCount: Int = 0

    /// 上传进度
    private var uploadProgress: Double = 0.0

    /// 已上传个数
    private var uploadedCount: Int = 0

    /// 总任务数
    private var totalTaskCount: Int = 0

    /// 记录当前的上传任务
    private var currentUploadTask: WmcUploadImageV2Model?

    /// 临时的无水印图片缓存路径
    private var imageFilePath: String = "WmcImageTemp/NoWaterMarkImages"

    /// 提交水印信息的request
    private var applyRequest: YPNetworkRequest?

    /// 当前上传任务
    private var currentUploadingRequest: Request?

    /// 新增任务到队列
    private func appendUploadQueue(model: WmcUploadImageV2Model) {
        model.uploading = true
        awaitUploadQueue.append(model)
        totalTaskCount += 1
        let progress = Double(uploadedCount) + uploadProgress
        let progressValue = convertToProgress(progress)
        DispatchQueue.main.async { [weak self] in
            guard let weakSelf = self else { return }
            weakSelf.progressSubject.onNext(progressValue)
        }
        startUploadTask()
    }

    /// 移除已完成的任务
    private func removeTaskFromUploadQueue(model: WmcUploadImageV2Model, completion: ((Bool) -> Void)? = nil) {
        var index = -1
        for (i, item) in awaitUploadQueue.enumerated() {
            if model.uuid == item.uuid {
                index = i
                break
            }
        }
        if index >= 0 {
            awaitUploadQueue.remove(at: index)
            WmcUploadQueueV2DBManager.delete(model: model) { isSuccess in
                completion?(isSuccess)
            }
        } else {
            completion?(false)
        }
    }

    /// 开始上传任务
    private func startUploadTask() {
        if self.uploading {
            return
        }

        if self.awaitUploadQueue.isEmpty {
            return
        }

        uploadImage()
        uploading = true

        DispatchQueue.main.async { [weak self] in
            guard let weakSelf = self else { return }
            weakSelf.startSubject.onNext(())
        }
    }

    private func applyUploadImagePath(model: WmcMediaUploadResourceParameterModel, success: @escaping ((WmcMediaUploadResourceModel) -> Void), failure: @escaping (Error?) -> Void) {
        // 水印相机内部所有上传都用101锁死
        model.appId = 101
        guard let paramsDict = model.toJSON() else { return }

        WmcMediaUploadAPI.applyUploadUrl(paramsDict: paramsDict, appId: "\(model.appId)") { [weak self] result in
            guard let weakSelf = self else { return }
            weakSelf.applyRetryCount = 0
            success(result)
        } failure: { [weak self] error in
            guard let weakSelf = self else { return }
            weakSelf.applyRetryCount += 1
            
            if weakSelf.applyRetryCount > 2 {
                failure(error)
            } else {
                if let err = error as? YPNetworkError, err.customErrorCode != 401 {
                    weakSelf.applyUploadImagePath(model: model, success: success, failure: failure)
                } else {
                    failure(error)
                }
            }
        }
    }

    private func uploadImageToAliyunOSS(fileURL: URL, model: WmcMediaUploadResourceModel, success: @escaping () -> Void, failure: @escaping (YPNetworkError) -> Void) {
        self.currentUploadingRequest = WmcMediaUploadAPI.uploadImage(fileURL: fileURL, uploadUrl: model.uploadUrl, header: model.headers) { [weak self] progress in
            guard let weakSelf = self else { return }
            weakSelf.uploadProgress = progress
            let progress = Double(weakSelf.uploadedCount) + progress
            let progressValue = weakSelf.convertToProgress(progress)
            DispatchQueue.main.async {
                weakSelf.progressSubject.onNext(progressValue)
            }
        } completion: { [weak self] in
            guard let weakSelf = self else { return }
            weakSelf.uploadRetryCount = 0
            weakSelf.uploadedCount += 1
            success()
        } failure: { [weak self] error in
            guard let weakSelf = self else { return }
            weakSelf.uploadRetryCount += 1

            if weakSelf.uploadRetryCount > 2 {
                failure(error)
            } else {
                weakSelf.uploadImageToAliyunOSS(fileURL: fileURL, model: model, success: success, failure: failure)
            }
        }
    }

    private func uploadImage() {
        guard let taskModel = awaitUploadQueue.last else {
            resetAllStatus()
            return
        }

        currentUploadTask = taskModel

        guard let params = WmcMediaUploadResourceParameterModel.deserialize(from: taskModel.parameters) else {
            uploadFailure()
            return
        }

        let filePath = YPSystem.Documents.Path.yp.appendPathComponent(taskModel.photoPath)
        let fileURL: URL = .init(fileURLWithPath: filePath)

        applyUploadImagePath(model: params) { [weak self] resource in
            guard let weakSelf = self else { return }
            weakSelf.uploadImageToAliyunOSS(fileURL: fileURL, model: resource) { [weak self] in
                guard let weakSelf = self else { return }

                let removeTask: () -> Void = {
                    weakSelf.currentUploadTask = nil

                    weakSelf.removeTaskFromUploadQueue(model: taskModel) { [weak self] isSuccess in
                        guard let weakSelf = self else { return }
                        if isSuccess {
                            if taskModel.photoPath.contains(weakSelf.imageFilePath) {
                                weakSelf.deleteImage(imagePath: taskModel.photoPath)
                            }

                            if weakSelf.awaitUploadQueue.isEmpty {
                                weakSelf.completionSubject.onNext(())
                                weakSelf.resetAllStatus()
                            } else {
                                weakSelf.uploadImage()
                            }
                        }
                    }
                }

                if let syncInfo = taskModel.syncInfo {
                    weakSelf.submitResource(resourceId: "\(resource.resourceId)", info: syncInfo) {
                        weakSelf.taskUploadSuccessSubject.onNext(taskModel)
                        removeTask()
                    } failure: { [weak self] error in
                        guard let weakSelf = self else { return }
                        /// 如果是因为退出团队报错的话，通过拦截器弹alertView，不弹toast，移除上传任务
                        if let error = error as? YPNetworkError, error.customErrorCode == 40003 {
                            removeTask()
                            weakSelf.uploadFailure(false)
                        } else {
                            weakSelf.uploadFailure()
                        }
                    }
                } else {
                    weakSelf.taskUploadSuccessSubject.onNext(taskModel)
                    removeTask()
                }
            } failure: { [weak self] error in
                guard let weakSelf = self else { return }
                weakSelf.uploadFailure()
            }
        } failure: { [weak self] error in
            guard let weakSelf = self else { return }
            weakSelf.uploadFailure()
        }
    }

    private func submitResource(resourceId: String, info: [String: Any], success: @escaping () -> Void, failure: @escaping (Error) -> Void) {
        WmcMediaTeamAlbumAPI.syncResource(resourceIds: [resourceId], albumBasicsInfo: info).subscribe(onNext: { _ in
            success()
        }, onError: { error in
            failure(error)
        }).disposed(by: rx.disposeBag)
    }

    private func getFileData(model: WmcMediaUploadImageParameterModel, path: String) -> Data? {
        let filePath = YPSystem.Documents.Path.yp.appendPathComponent(path)

        var uploadData: Data?

        if model.type == 0 {
            if let img = UIImage(contentsOfFile: filePath), let data = img.pngData() {
                uploadData = data
            }
        } else {
            if let data = FileManager.default.contents(atPath: filePath) {
                uploadData = data
            }
        }

        return uploadData
    }

    private func uploadFailure(_ isShowError: Bool = true) {
        currentUploadTask = nil

        if self.uploading {
            DispatchQueue.main.async {
                if isShowError {
                    WmcHudManager.toast("网络不佳，请稍后再试")
                }
                self.resetAllStatus()
                self.failureSubject.onNext(())
            }
        }
    }

    private func deleteImage(imagePath: String) {
        let path = YPSystem.Documents.Path.yp.appendPathComponent(imagePath)
        if self.fileManager.fileExists(atPath: path) {
            do {
                try self.fileManager.removeItem(atPath: path)
            } catch let error {
                log("删除图片失败, error: \(error.localizedDescription)")
            }
        }
    }

    private func convertToProgress(_ progress: Double) -> Double {
        let totalTaskCount = Double(self.totalTaskCount)
        var progressValue = 1.0
        if progress >= 0.0, progress < totalTaskCount {
            progressValue = progress / totalTaskCount
        }
        return progressValue
    }

    private func querySyncData(configList: [WmcMediaAlbumConfigurationModel]) -> [String: Any] {
        var list: [[String: Any]] = []

        configList.forEach { item in
            if item.isSync {
                let dict: [String: Any] = ["albumId": item.albumId, "busId": item.busId, "albumType": item.albumType]
                list.append(dict)
            }
        }

        let result: [String: Any] = ["albumBasicsInfo": list]
        return result
    }

    

    private func resetAllStatus() {
        DispatchQueue.main.async { [weak self] in
            guard let weakSelf = self else { return }
            weakSelf.uploading = false
            weakSelf.applyRetryCount = 0
            weakSelf.uploadRetryCount = 0
            weakSelf.uploadProgress = 0.0
            weakSelf.uploadedCount = 0
            weakSelf.totalTaskCount = 0
            weakSelf.awaitUploadQueue.removeAll()
            weakSelf.applyRequest = nil
            weakSelf.currentUploadingRequest = nil
        }
    }
}
